package com.lambkit.module.upms;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.lambkit.auth.AuthConfig;
import com.lambkit.auth.AuthSession;
import com.lambkit.auth.AuthUser;
import com.lambkit.core.Lambkit;
import com.lambkit.core.http.IHttpContext;
import com.lambkit.core.http.IRequest;
import com.lambkit.module.upms.auth.service.UpmsDataService;
import com.lambkit.module.upms.kernel.UpmsVerifyResult;
import com.lambkit.module.upms.row.UpmsLog;
import com.lambkit.module.upms.row.UpmsPermission;
import com.lambkit.module.upms.row.UpmsUser;
import com.lambkit.module.upms.service.UpmsPermissionService;
import com.lambkit.util.RequestKit;
import com.lambkit.web.WebConfig;
import com.lambkit.web.log.UniqueVisitorLogService;

import java.io.IOException;
import java.util.Map;

/**
 * @author yangyong(孤竹行)
 */
public class UpmsLoginValidator {
    public boolean validate(IHttpContext context) {
        UpmsConfig upmsConfig = Lambkit.config(UpmsConfig.class);
        // 登录信息
        UpmsKernel upmsKernel = Upms.use(context.getRequest());
        System.out.println("Lambkit upms interceptor ---------------------------------");
//        System.out.println("startTime      : " + DateTimeUtils.dateToString(session.getStartTimestamp()));
//        System.out.println("lastAccessTime : " + DateTimeUtils.dateToString(session.getLastAccessTime()));
//        System.out.println("timeout        : " + session.getTimeout());
        String serverSessionId = upmsKernel.getSessionId();
        System.out.println("sessionId      : " + serverSessionId);
        String code = upmsKernel.getCache().getSession(serverSessionId);
        System.out.println("sessonCode     : " + code);
        String username = (String) upmsKernel.getAuthId();
        System.out.println("username       : " + username);
        System.out.println("----------------------------------------------------------");
        UpmsUser upmsUser = null;
        if (StrUtil.isNotBlank(username)) {
            upmsUser = Upms.getApiService().selectUpmsUserByUsername(username);
            context.setAttr("upmsUser", upmsUser);
            context.setAttr("upmsCode", username);
        } else if (StrUtil.isNotBlank(code)) {
            String[] codes = code.split("&");
            username = codes[1];
            //再次登录，这里有风险，请后续优化完善
            AuthUser authUser = Upms.getAuthDataService().getAuthUser(username);
            serverSessionId = upmsKernel.getAuthKernelService().login(authUser);
            upmsUser = (UpmsUser) authUser.getUserBean();
            context.setAttr("upmsUser", upmsUser);
            context.setAttr("upmsCode", username);
        } else {
            AuthConfig config = Lambkit.config(AuthConfig.class);
            if (!"server".equalsIgnoreCase(config.getType()) && StrUtil.isNotBlank(upmsConfig.getServerSsoUrl())) {
                username = validateFromServer(context.getRequest(), upmsKernel);
                if (StrUtil.isNotBlank(username)) {
                    upmsUser = Upms.getApiService().selectUpmsUserByUsername(username);
                    context.setAttr("upmsUser", upmsUser);
                    context.setAttr("upmsCode", username);
                }
            }
        }

        UpmsPermission upmsPermission = null;
        if (upmsConfig.isActiveUpmsPermission()) {
            String target = context.getTarget();
            upmsPermission = Lambkit.get(UpmsPermissionService.class).findFirstByCacheAndUri(target);
            if (upmsPermission == null) {
                upmsPermission = new UpmsPermission();
                //upmsPermission.setSystemId(6L);
                upmsPermission.setType(0);
                upmsPermission.setIcon(target);//inv.getController().getClass().getName() + "." + inv.getMethodName());
                upmsPermission.setUri(target);
                upmsPermission.setPermissionValue(target.substring(1).replaceAll("/", ":"));
                upmsPermission.setName(upmsPermission.getPermissionValue());
                upmsPermission.setStatus(0);
                Lambkit.get(UpmsPermissionService.class).dao().save(upmsPermission);
            }
        }
        boolean hasRule = false;
        //用户权限校验1-未校验，200校验通过，其他（401，403）-校验失败
        int ruleCheckCode = 1;//upmsKernel.validation(inv, upmsUser);
        if (ruleCheckCode == 200) {
            hasRule = true;
        } else if (ruleCheckCode == 1) {
            //其他拦截器已经校验过
            UpmsVerifyResult upmsVerifyResult = context.getAttr("upmsVerify");
            if (upmsVerifyResult != null && upmsVerifyResult.isAllowAccess()) {
                // 其他kernel已经给了权限
                System.out.println("upms-permission：" + upmsVerifyResult.getKernelName() + " 已经给了权限");
                hasRule = true;
            } else if (upmsPermission.getStatus() == -1) {
                //System.out.println("upms-permission：该接口已锁定");
                doProcessUnauthenticated(context);
                return false;
            } else if (upmsPermission.getStatus() == 0) {
                // 该接口不需要权限控制
                System.out.println("upms-permission：该接口不需要权限控制");
                context.setAttr("upmsVerify", UpmsVerifyResult.create(upmsKernel.getName(), hasRule));
                hasRule = true;
            } else if (StrUtil.isBlank(username)) {
                System.out.println("upms-permission：未登录");
                doProcessUnauthenticated(context);
                return false;
            } else {
                if (upmsUser == null) {
                    // 未登录
                    //inv.getController().redirect("/login");
                    System.out.println("upms-permission：未登录");
                    doProcessUnauthenticated(context);
                    return false;
                } else {
                    if (upmsKernel.hasRule(upmsUser, upmsPermission.getPermissionId())) {
                        // 有权限
                        System.out.println("upms-permission：有权限");
                        hasRule = true;
                    } else if (upmsPermission.getStatus() == 1) {
                        // 该接口需要登录即可获得权限控制
                        System.out.println("upms-permission：已登录的用户即可获得该接口的权限控制");
                        context.setAttr("upmsVerify", UpmsVerifyResult.create(upmsKernel.getName(), hasRule));
                        hasRule = true;
                    } else if (upmsKernel.hasAnyRoles(upmsUser, "super")) {
                        // 有权限
                        System.out.println("upms-permission：超级管理员");
                        hasRule = true;
                    } else {
                        System.out.println("upms-permission：无权限");
                    }
                    if (hasRule) {
                        context.setAttr("upmsVerify", UpmsVerifyResult.create(upmsKernel.getName(), hasRule));
                    }
                }
            }
        } else {
            if (ruleCheckCode == 401) {
                doProcessUnauthenticated(context);
            } else {
                doProcessUnauthorization(context);
            }
        }

        if (hasRule) {
            long startTime = System.currentTimeMillis();
            context.setAttr("upmsLoginValidatorStartTime", startTime);
            settingAuthSession(context, serverSessionId, 1, true);
            return true;
            //log(context);
        } else {
            doProcessUnauthorization(context);
            //inv.getController().renderError(403);
        }
        return false;
    }

    public void log(IHttpContext context) {
        UpmsLog upmsLog = context.getAttr("upmsLogForHttp");
        Long startTime = context.getAttr("upmsLoginValidatorStartTime");
        if (upmsLog != null) {
            long endTime = System.currentTimeMillis();
            if (startTime != null) {
                Integer spendTime = (int) (endTime - startTime);
                upmsLog.setSpendTime(spendTime);
            }
            Upms.getApiService().insertUpmsLogSelective(upmsLog);
        }

        UniqueVisitorLogService uniqueVisitorLogService = Lambkit.get(UniqueVisitorLogService.class);
        if (uniqueVisitorLogService != null) {
            uniqueVisitorLogService.log(context);
        }
    }

    private void settingAuthSession(IHttpContext context, String sessionId, int status, boolean isExpired) {
        AuthSession session = context.getAttr("authSession");
        if(session==null) {
            session = new AuthSession();
        }
        session.setHost(RequestKit.getIpAddress(context.getRequest()));
        session.setUserAgent(RequestKit.getUserAgent(context.getRequest()));
        session.setLastAccessTime(System.currentTimeMillis());
        session.setId(sessionId);
        session.setStatus(status);
        session.setExpired(isExpired);
        context.setAttr("authSession", session);
    }

    /**
     * 未认证处理
     */
    private void doProcessUnauthenticated(IHttpContext context) {
//        if(method.isAnnotationPresent(ResponseBody.class)) {
//            context.renderError(401, "未认证");
//            return;
//        }
        AuthConfig config = Lambkit.config(AuthConfig.class);
        WebConfig webConfig = Lambkit.config(WebConfig.class);
        if("redirect".equals(webConfig.getErrorRenderType())) {
            //controller.redirect(config.getLoginUrl());
            StringBuffer sso_server_url = new StringBuffer(config.getLoginUrl());
            //String upmsType = upmsConfig.getType();
            String url = sso_server_url.append(config.getLoginUrl()).toString();
            if(url.startsWith("//")) {
                url = url.substring(2);
            }
            if(url.startsWith("/")) {
                url = url.substring(1);
            }
            System.out.println("未认证处理, 跳转到 " + url);
            try {
                context.getResponse().redirect(url);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            context.renderError(401, "未认证");
        }

    }

    /**
     * 未授权处理
     */
    private void doProcessUnauthorization(IHttpContext context) {
//        if(method.isAnnotationPresent(ResponseBody.class)) {
//            controller.renderError(403);
//            return;
//        }
        AuthConfig config = Lambkit.config(AuthConfig.class);
        WebConfig webConfig = Lambkit.config(WebConfig.class);
        if("redirect".equals(webConfig.getErrorRenderType())) {
            String url = config.getUnauthorizedUrl();
            if(url.startsWith("/")) {
                url = url.substring(1);
            }
            System.out.println("未授权处理, 跳转到 " + url);
            try {
                context.getResponse().redirect(url);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else {
            context.renderError(403, "未授权");
        }
    }

    /**
     * 强制退出
     * @param controller
     */
//    private void doProcessuSessionForceLogout(Controller controller) {
//    	SecurityUtils.getSubject().logout();
//    	if (StrUtil.isBlank(config.getLoginUrl())) {
//            controller.renderError(401);
//            return;
//        }
//        String loginUrl = config.getLoginUrl() + (config.getLoginUrl().contains("?") ? "&" : "?") + "forceLogout=1";
//        try {
//			WebUtils.issueRedirect(controller.getRequest(), controller.getResponse(), loginUrl);
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//        //controller.redirect(config.getUnauthorizedUrl());
//    }

    /**
     * client模式下，采用http方式实时校验用户
     * @return
     */
    public String validateFromServer(IRequest request, UpmsKernel upmsKernel) {
        UpmsConfig upmsConfig = Lambkit.config(UpmsConfig.class);
        String sessionId = Upms.use(request).getSessionId();
        Map<String, Object> params = MapUtil.newHashMap();
        params.put("appid", upmsConfig.getAppId());
        params.put("sessionid", sessionId);
        String usernameResult = null;
        try {
            JSONObject result = JSONObject.parseObject(HttpUtil.get(upmsConfig.getServerSsoUrl() + "/authenticate", params));
            if(Lambkit.context().isDevMode()) {
                System.out.println("result:"+result.getIntValue("code") + ", message:"+result.getString("message") + ", data:" + result.getString("data"));
            }
            if(result == null || 0 == result.getIntValue("code")) {
                // 认证失败
                String username = Upms.use(request).getAuthId();
                if (StrUtil.isNotBlank(username)) {
                    Upms.use(request).forceout(username);
                }
                return usernameResult;
            } else {
                //本地是否登录
                String username = Upms.use(request).getAuthId();
                if (StrUtil.isBlank(username) || username.equals("null")) {
                    // client无密认证
                    username = result.getString("message");
                    if(Lambkit.context().isDevMode()) {
                        System.out.println("client login: " + username);
                    }
                    AuthUser authUser = Lambkit.get(UpmsDataService.class).getAuthUser(username);
                    upmsKernel.getAuthKernelService().login(authUser);
                    usernameResult = username;
                }
            }
            return usernameResult;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return usernameResult;
    }
}
